{{>licenseInfo}}
{{#models}}{{#model}}/*
 * {{classname}}.h
 *
 * {{description}}
 */

#ifndef {{modelHeaderGuardPrefix}}_{{classname}}_H_
#define {{modelHeaderGuardPrefix}}_{{classname}}_H_

{{#hasEnums}}
#include <stdexcept>
{{/hasEnums}}
{{#oneOf}}
{{#-first}}
#include <variant>
{{/-first}}
{{/oneOf}}
#include <boost/optional.hpp>
{{^parent}}
{{{defaultInclude}}}
#include "{{packageName}}/ModelBase.h"
{{/parent}}

{{#imports}}{{{this}}}
{{/imports}}

{{#modelNamespaceDeclarations}}
namespace {{this}} {
{{/modelNamespaceDeclarations}}

{{#vendorExtensions.x-has-forward-declarations}}
{{#vendorExtensions.x-forward-declarations}}{{.}}
{{/vendorExtensions.x-forward-declarations}}
{{/vendorExtensions.x-has-forward-declarations}}
{{#oneOf}}{{#-first}}

class {{declspec}} {{classname}}
{
public:
    {{classname}}() = default;
    ~{{classname}}() = default;

    /////////////////////////////////////////////

    void validate();

    web::json::value toJson() const;

    template<typename Target>
    bool fromJson(const web::json::value& json) {
        // convert json to Target type
        Target target;
        if (!target.fromJson(json)) {
            return false;
        }

        m_variantValue = target;
        return true;
    }

    void toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) const;

    template<typename Target>
    bool fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) {
        // convert multipart to Target type
        Target target;
        if (!target.fromMultiPart(multipart, namePrefix)) {
            return false;
        }

        m_variantValue = target;
        return true;
    }

    /////////////////////////////////////////////
    /// {{classname}} members

    using VariantType = std::variant<{{#oneOf}}{{^-first}}, {{/-first}}{{{.}}}{{/oneOf}}>;

    const VariantType& getVariant() const;
    void setVariant(VariantType value);

protected:
    VariantType m_variantValue;
};

{{/-first}}{{/oneOf}}
{{^oneOf}}
{{#isEnum}}
class {{declspec}} {{classname}}
    : public {{{parent}}}{{^parent}}ModelBase{{/parent}}
{
public:
    {{classname}}();
    {{classname}}(utility::string_t str);
    operator utility::string_t() const {
        return enumToStrMap.at(getValue());
    }

    {{! operator std::string() const {
        return enumToStrMap.at(getValue());
    } }}

    virtual ~{{classname}}();

    /////////////////////////////////////////////
    /// ModelBase overrides

    void validate() override;

    web::json::value toJson() const override;
    bool fromJson(const web::json::value& json) override;

    void toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) const override;
    bool fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) override;

    enum class e{{classname}}
    {
        {{#allowableValues}}
        {{#enumVars}}
        {{#enumDescription}}
        /// <summary>
        /// {{.}}
        /// </summary>
        {{/enumDescription}}
        {{{name}}}{{^last}},{{/last}}
        {{/enumVars}}
        {{/allowableValues}}
    };

    e{{classname}} getValue() const;
    void setValue(e{{classname}} const value);

    protected:
        e{{classname}} m_value;
        std::map<e{{classname}},utility::string_t> enumToStrMap = {
        {{#allowableValues}}
        {{#enumVars}}
        { e{{classname}}::{{{name}}}, _XPLATSTR("{{{name}}}") }{{^-last}},{{/-last}}
        {{/enumVars}}
        {{/allowableValues}}
};
        std::map<utility::string_t,e{{classname}}> strToEnumMap = {
        {{#allowableValues}}
        {{#enumVars}}
        { _XPLATSTR("{{{name}}}"), e{{classname}}::{{{name}}} }{{^-last}},{{/-last}}
        {{/enumVars}}
        {{/allowableValues}}
};

};
{{/isEnum}}
{{^isEnum}}

{{#description}}
/// <summary>
/// {{description}}
/// </summary>
{{/description}}
class {{declspec}} {{classname}}
    : public {{{parent}}}{{^parent}}ModelBase{{/parent}}
{
public:
    {{classname}}();
    virtual ~{{classname}}();

    /////////////////////////////////////////////
    /// ModelBase overrides

    void validate() override;

    web::json::value toJson() const override;
    bool fromJson(const web::json::value& json) override;

    void toMultipart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) const override;
    bool fromMultiPart(std::shared_ptr<MultipartFormData> multipart, const utility::string_t& namePrefix) override;


    /////////////////////////////////////////////
    /// {{classname}} members

    {{! ENUM DEFINITIONS }}
    {{#vars}}
    {{^isInherited}}
    {{#isEnum}}
    enum class {{#isContainer}}{{{enumName}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}{{/isContainer}}
    {
        {{#allowableValues}}
        {{#enumVars}}
        {{{name}}}{{^last}},{{/last}}
        {{/enumVars}}
        {{/allowableValues}}
    };
    {{#description}}
    /// <summary>
    /// {{description}}
    /// </summary>
    {{/description}}
    {{/isEnum}}
    {{/isInherited}}
    {{/vars}}
    {{#vars}}
    {{^isInherited}}
    {{#isEnum}}
    {{#isContainer}}
    {{! ENUM CONVERSIONS }}
    {{{enumName}}} to{{{enumName}}}(const utility::string_t& value) const;
    const utility::string_t from{{{enumName}}}(const {{{enumName}}} value) const;
    {{#isArray}}
    {{{datatypeWithEnum}}} to{{{enumName}}}(const {{{dataType}}}& value) const;
    {{{dataType}}} from{{{enumName}}}(const {{{datatypeWithEnum}}}& value) const;
    {{/isArray}}{{/isContainer}}{{^isContainer}}
    {{{datatypeWithEnum}}} to{{{datatypeWithEnum}}}(const utility::string_t& value) const;
    const utility::string_t from{{{datatypeWithEnum}}}(const {{{datatypeWithEnum}}} value) const;
    {{/isContainer}}

    {{/isEnum}}
    {{/isInherited}}
    {{/vars}}

    {{! SETTER AND GETTERS }}
    {{#vars}}
    {{^isInherited}}
    {{#description}}
    /// <summary>
    /// {{description}}
    /// </summary>
    {{/description}}
    {{#isContainer}}
    {{^isEnum}}
    {{{dataType}}} {{getter}}() const;
    {{/isEnum}}
    {{/isContainer}}
    {{^isContainer}}
    {{^isEnum}}
    {{{dataType}}} {{getter}}() const;
    {{/isEnum}}
    {{/isContainer}}
    {{#isEnum}}
    {{^isMap}}
    {{{datatypeWithEnum}}} {{getter}}() const;
    {{/isMap}}
    {{#isMap}}
    {{{dataType}}} {{getter}}() const;
    {{/isMap}}
    {{/isEnum}}
    bool {{nameInCamelCase}}IsSet() const;
    void unset{{name}}();
    {{#isPrimitiveType}}
    void {{setter}}({{{dataType}}} value);
    {{/isPrimitiveType}}
    {{^isPrimitiveType}}
    {{^isEnum}}
    void {{setter}}(const {{{dataType}}}& value);
    {{/isEnum}}
    {{/isPrimitiveType}}
    {{#isEnum}}
    void {{setter}}(const {{^isMap}}{{{datatypeWithEnum}}}{{/isMap}}{{#isMap}}{{{dataType}}}{{/isMap}} value);
    {{/isEnum}}
    {{/isInherited}}

    {{/vars}}

protected:
    {{#vars}}
    {{^isInherited}}
    {{#isNullable}}
    {{^isEnum}}
    boost::optional<{{{dataType}}}> m_{{name}};
    {{/isEnum}}
    {{#isEnum}}
    boost::optional<{{^isMap}}{{{datatypeWithEnum}}}{{/isMap}}{{#isMap}}{{{dataType}}}{{/isMap}}> m_{{name}};
    {{/isEnum}}
    {{/isNullable}}
    {{^isNullable}}
    {{^isEnum}}
    {{{dataType}}} m_{{name}};
    {{/isEnum}}
    {{#isEnum}}
    {{^isMap}}{{{datatypeWithEnum}}}{{/isMap}}{{#isMap}}{{{dataType}}}{{/isMap}} m_{{name}};
    {{/isEnum}}
    bool m_{{name}}IsSet;
    {{/isNullable}}
    {{/isInherited}}

    {{/vars}}
};

{{/isEnum}}
{{/oneOf}}

{{#modelNamespaceDeclarations}}
}
{{/modelNamespaceDeclarations}}

#endif /* {{modelHeaderGuardPrefix}}_{{classname}}_H_ */
{{/model}}
{{/models}}
